Skip to content

fix(booking-ui): the consultee can finally answer a reschedule proposal - #1177

Merged
teetangh merged 1 commit into
devfrom
fix/reschedule-lifecycle-ui
Aug 14, 2026
Merged

fix(booking-ui): the consultee can finally answer a reschedule proposal#1177
teetangh merged 1 commit into
devfrom
fix/reschedule-lifecycle-ui

Conversation

@teetangh

Copy link
Copy Markdown
Contributor

Stacks on #1174 (PR 4a, fix/reschedule-cancel-lifecycle) and merges AFTER it — until then this diff shows 4a's commit too. UI half of the reschedule response loop: 4a shipped the respond endpoint and the proposal-carrying reads; this PR gives them their callers.

What changed

Consultee proposal card (RescheduleProposalCard, mounted on the shared appointment detail page): renders the open rescheduleRequests[0] — who proposed, the current round's times in the viewer's locale, the reason, the expiry. The counterparty (session user ≠ initiatedById) gets Accept and a confirmed Decline whose dialog spells out that the released times stay with the consultant to re-place — declining is not cancelling. The initiator gets Withdraw. Mutations POST …/reschedule/respond {action} / …/reschedule/withdraw, relay the server's message in the toast, disable in flight, and invalidate the appointment-detail + consultee-events caches. A COUNTERED request shows only the current round's offer.

List rows: an open proposal adds a "Review reschedule request" overflow item that navigates to the appointment CARRYING the proposal — for a subscription that is not necessarily the row's anchor child. The detail page filters that item out because the card is already there.

Consultant inbox (RequestSlotAllocationTab): "Use Requested Times" is no longer suppressed when an open PENDING_REVIEW consultee proposal names concrete times — the dialog then previews the PROPOSED times and confirm routes through respond-accept (full allocator under the wide lock, finalizes the request ACCEPTED) instead of the allocate PATCH, which would have confirmed times while leaving the request dangling open. Consultant-countered (COUNTERED) and preference-only proposals stay suppressed. Decline gains a confirm dialog and a SUBSCRIPTION arm (that PATCH's consultant-only REJECTED path); both flows disable in flight.

Trial guard: the consultee reschedule page refuses TRIAL subjects with a friendly message instead of drawing a picker whose submit can only 403.

Invalidation fix (useEventActions): cancel/reschedule success now always invalidates the appointment-detail key, and the hook takes the adapter's resolved consulteeId instead of trusting useParams — on the org detail route (no [consulteeId] param) every invalidation was a silent no-op.

Misplaced include removed: the webinar-side rescheduleRequests include comes off the consultee events read — proposals exist only for CONSULTATION/SUBSCRIPTION (supportsProposals), so it was a per-row subquery that could never match. The subscription branch gains the include it was missing, and proposedSlots selects gain round for parity with the detail read.

Tests

  • consultee-affordances.test.ts — unit coverage for the new openProposalTarget / currentRoundProposedSlots helpers (anchor-vs-sibling targeting, countered-round filtering).
  • reschedule-respond-ui.test.ts (new) — source contracts: the respond endpoint has UI callers and withdraw has one; identity-split affordances; decline-is-not-cancel confirm; inbox answerability gates; the trial refusal.
  • tsc --noEmit cold: clean. eslint on all touched files: zero errors, zero warnings. Full jest: 2772 passed; the 5 failing suites (razorpay-credential/env-shaped) fail identically on the base commit.

Closes #1163. Part of #1169.

🤖 Generated with Claude Code

https://claude.ai/code/session_01SbUWhJASnqTFT9evn8YJVx

@netlify

netlify Bot commented Aug 14, 2026

Copy link
Copy Markdown

Deploy Preview for familiarise ready!

Name Link
🔨 Latest commit f215fef
🔍 Latest deploy log https://app.netlify.com/projects/familiarise/deploys/6a7fa90e2b71310008500762
😎 Deploy Preview https://deploy-preview-1177--familiarise.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.
Lighthouse
Lighthouse
1 paths audited
Performance: 38 (🔴 down 14 from production)
Accessibility: 90 (no change from production)
Best Practices: 83 (no change from production)
SEO: 82 (no change from production)
PWA: -
View the detailed breakdown and full score reports

To edit notification comments on pull requests, go to your Netlify project configuration.

@coderabbitai

coderabbitai Bot commented Aug 14, 2026

Copy link
Copy Markdown

Warning

Review limit reached

@teetangh, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 5 minutes

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: b342bee7-39c9-4d1a-ba64-23e06133fdf9

📥 Commits

Reviewing files that changed from the base of the PR and between d8cdad1 and f215fef.

📒 Files selected for processing (12)
  • __tests__/booking-algorithm/consultee-affordances.test.ts
  • __tests__/booking-algorithm/reschedule-respond-ui.test.ts
  • app/dashboard/consultee/[consulteeId]/(features)/appointments/[appointmentId]/reschedule/page.tsx
  • components/appointments/consultee/ConsulteeAppointmentsAdapter.tsx
  • components/appointments/consultee/useEventActions.ts
  • components/appointments/detail/AppointmentDetailClient.tsx
  • components/appointments/detail/RescheduleProposalCard.tsx
  • components/dashboard/shared/requests/RequestSlotAllocationTab.tsx
  • components/dashboard/shared/requests/components/RequestedSlotsDialog.tsx
  • lib/appointments/consultee-affordances.ts
  • lib/data/appointment-detail.ts
  • lib/data/consultee-events-read.ts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

teetangh added a commit that referenced this pull request Aug 14, 2026
The #1169 train's wave-1 PRs carried their own documentation; the late
ones (#1174, #1177, #1178, #1179, #1180) shipped without changelog rows.
Adds 21 rows to the August 2026 table, each verified against the PR diff
rather than the PR description, plus a note in 01-architecture recording
that the client auto-allocator is gone and the grid now polls.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SbUWhJASnqTFT9evn8YJVx
@teetangh
teetangh force-pushed the fix/reschedule-lifecycle-ui branch from ce6d02d to b495cda Compare August 14, 2026 23:12
…al (#1169 PR 4b)

The detail page grows a proposal card off the live rescheduleRequests
read: the counterparty gets Accept and a confirmed Decline that spells
out that the released times stay with the consultant — declining is not
cancelling — and the initiator gets Withdraw. Toasts relay the server's
message, and success invalidates the detail and events caches. List rows
with an open proposal navigate to the appointment that carries it, which
for a subscription is not necessarily the anchor child.

The consultant inbox stops suppressing "Use Requested Times" when an
open consultee proposal names concrete times — the button then answers
through respond-accept (full allocator under the wide lock) instead of
the allocate PATCH, which would have confirmed the times while leaving
the request dangling open. Decline gains a confirm dialog and a
subscription arm (that PATCH's consultant-only REJECTED path, #1004),
both disabled in flight.

The consultee reschedule page refuses TRIAL subjects with a friendly
message instead of drawing a picker whose submit can only 403. And
useEventActions now always invalidates the appointment-detail key and
takes the adapter's resolved consulteeId instead of trusting useParams,
which on the org detail route made every invalidation a silent no-op.

The webinar-side rescheduleRequests include comes OFF the events read —
proposals exist only for CONSULTATION/SUBSCRIPTION (supportsProposals),
so it was a per-row subquery that could never match.

Closes #1163. Part of #1169.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SbUWhJASnqTFT9evn8YJVx
@teetangh
teetangh force-pushed the fix/reschedule-lifecycle-ui branch from b495cda to f215fef Compare August 14, 2026 23:47
@sonarqubecloud

Copy link
Copy Markdown

@teetangh
teetangh merged commit 038ecb8 into dev Aug 14, 2026
8 checks passed
@teetangh
teetangh deleted the fix/reschedule-lifecycle-ui branch August 14, 2026 23:59
teetangh added a commit that referenced this pull request Aug 15, 2026
The #1169 train's wave-1 PRs carried their own documentation; the late
ones (#1174, #1177, #1178, #1179, #1180) shipped without changelog rows.
Adds 21 rows to the August 2026 table, each verified against the PR diff
rather than the PR description, plus a note in 01-architecture recording
that the client auto-allocator is gone and the grid now polls.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SbUWhJASnqTFT9evn8YJVx
teetangh added a commit that referenced this pull request Aug 15, 2026
…index the prompts corpus (#1171)

* docs(collaborators): rewrite all seven files against the merged Collaborator model

The collaborators folder was the worst-drift band in the repo: it still
documented the deleted WebinarCollaborator/ClassCollaborator models and
their per-type role enums (merged into one Collaborator model by #784),
a permissions JSON override (replaced by four typed booleans in #768, of
which only canSeeAttendees is enforced today), a nonexistent
lib/collaborators/permissions.ts module and checkWebinarPermission
function, and a float revenueSharePercentage column (revenueShareBps Int
since #772 B5). All seven files are rewritten from the current code:
service.ts, availability.ts (the AE-2 enforced co-host guard), the
collaboration routes, and the settlement path in earnings-service.ts
(pool-based split with floors per #778 §C-2, org settlement per #773,
verified Stream revocation per #1125).

Part of #1169.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SbUWhJASnqTFT9evn8YJVx

* docs(payments): re-verify every file:line citation in the funding-seam doc

The prose was correct but the line references had drifted: the Payment
model is at prisma/schema.prisma:4136-4242 (doc said 3515-3563),
FundingSource at :1100 (said 901), and the fundingSource resolution at
checkout.ts:1986 (said 1907). The remaining refs in the doc had drifted
the same way (PaymentLeg, WalletTopUp, skipPayment, walletDebit, and the
refund.ts audit/clawback/Step-9 blocks); each new number was verified
against the current files before writing. Also cross-links the new
booking-side page for this rail.

Part of #1169.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SbUWhJASnqTFT9evn8YJVx

* docs(booking): document the org-funded checkout rail

docs/booking/ documented the sponsored path nowhere. The new
17-org-funded-checkout.md covers, with verified file:line refs: the
shared checkout route with optional organizationId; the resolution chain
(canSponsor gate, overdue-invoice dunning suspension, ACTIVE membership,
DPDP consent, fundingSource from the org BillingAccount, INVOICE
credit-limit and verified-domain gates, ProgramAssignment resolution —
which fails closed rather than falling back to the learner's card — and
the ADR 18 allowlist/exclusivity gates inside the lock); the gateway
skip with synthetic org_* intents; the atomic conditional-updateMany
wallet debit; CLASS debiting N engagements at checkout while
SUBSCRIPTION debits lazily per allocation; and inline settlement with
the booking-journal posting, including what happens when the posting
fails after the booking has committed. The README quick-nav gains rows
for 15, 16 and the new 17.

Part of #1169.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SbUWhJASnqTFT9evn8YJVx

* docs(prompts): index the corpus, fix the ledger drift, reconcile the seed cohorts, add two booking cases

Four changes to the prompts corpus. (1) A new prompts/README.md indexes
the 43 prompt files by directory and states how the enterprise-tests
tree relates to docs/enterprise/90-audits/03-verification-guide.md.
(2) shared-setup.md stops teaching the deleted three-ledger models:
FundingLedgerEntry and SettlementLedgerEntry (and WalletEntry) were
replaced by the LedgerAccount/LedgerTransaction/LedgerEntry double-entry
journal plus UsageLedgerEntry in #772 — rule 2, the glossary section,
the webhook-idempotency note and the schema table are all corrected.
(3) The two documented seed cohorts are reconciled: the founder@*.test /
TestPassword123! roster in shared-setup §2 never existed in the seeds
(and its table swapped the IIT/LearnPro shapes); the verification
guide's SeedPass123! roster matches prisma/seedFiles/, so §2 now defers
to it and each doc points at the other. (4) Two new case files in the
Agent-005 template style: 007 covers the reschedule-proposal response
loop (lands with train PR 3, #1162) and 008 covers maintenance-freeze
correctness — a freeze must not destroy a PENDING payment, and
freeze-then-cancel must not double-refund (lands with train PR 4,
#1163); both carry explicit coverage markers. New files are added with
-f, matching how the ignored-but-tracked corpus is versioned.

Part of #1169.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SbUWhJASnqTFT9evn8YJVx

* docs(skills): add the booking-doctrine skill

Captures the booking subsystem's seven non-negotiable invariants for
future agents: CAS status transitions through lib/booking/transitions.ts
(the WHERE clause is the state machine); nothing is deleted (soft-cancel
via completionStatus and tombstones — never delete an appointment a
Payment points at, #1074); the two refund front doors and the three
intent rails (gateway pi_/cs_/order_/pay_, internal org_*, free_); the
one-lock-namespace rule under utils/appointmentlock.ts with the global
lock order; the prisma/sql sidecars applied via db:sidecars; explicit
org scoping with personal surfaces pinning organizationId null; and the
testing recipes (background dev server + mock data, never db push;
__tests__/booking-algorithm and __tests__/payments; chaos runbook).

Part of #1169.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SbUWhJASnqTFT9evn8YJVx

* docs(misc): ADR 20 no-drill-in addendum + booking changelog entry for the refresh

ADR 20 gains a dated addendum stating plainly that the org "Everyone"
appointments table is metadata-only by design — the missing row link is
intent, not a gap — so the 2026-08-13 audit finding stops being
re-reported as a bug. The booking troubleshooting doc gains a 2026-08-14
changelog section for this documentation refresh (#1169, closing #1013).

Part of #1169.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SbUWhJASnqTFT9evn8YJVx

* docs(skills): model-orchestration — the advisor/teacher/student tier split

Encodes the pattern that shipped the #1169 train and the session-budget
lesson that cost it four agent fleets: judgment on the advisor tier,
spec-following execution on the teacher tier, mechanical breadth on the
student tier, per-role effort levels, the commit-early limit clause, and
the resume-from-worktree recovery pattern. Placeholders left for team
defaults.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SbUWhJASnqTFT9evn8YJVx

* docs(booking): changelog rows for the late train PRs

The #1169 train's wave-1 PRs carried their own documentation; the late
ones (#1174, #1177, #1178, #1179, #1180) shipped without changelog rows.
Adds 21 rows to the August 2026 table, each verified against the PR diff
rather than the PR description, plus a note in 01-architecture recording
that the client auto-allocator is gone and the grid now polls.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SbUWhJASnqTFT9evn8YJVx

* docs: adversarial-review corrections — merged-reality alignment

Four corrections against merged dev, each verified before writing.

Rule 4 of the booking-doctrine skill listed `trial-slot-booking:` as a
live lock namespace. #1170 retired it entirely: trials now take the
shared `slot-booking:` atom keys, one key per 30-minute atom the booked
interval covers, floored to the half-hour grid. The rule also still
promised the consolidation as future work; it has landed.

`08-cancellation-flow.md` was untouched by this train despite the PR
claiming `Closes #1013`, and PRs 4 and 6 never picked it up either — the
file is byte-identical on dev. It still taught delete-on-cancel, no
authentication and no refunds, which are the three claims #1013 was
raised against. The walkthrough, every diagram, the record tables and
the error contract now match `cancel/route.ts`. The #1006 escalation for
partly-consumed subscriptions is gone: #1006 is closed and the linear
per-session proration replaced it, so the refundable base is
`floor(gross × sessionsRemaining / slotsTotal)` for subscriptions and
the policy tier applies to that base. The only surviving `MANUAL_REVIEW`
path is the credit-funded partial-window case (#1161).

The collaborators rewrite dropped a qualifier the pre-PR text had right:
`assertCollaboratorsAvailable()` is called from the webinar plan route
alone, so class-plan co-hosts have no availability guard. The over-claim
had spread to six files, all corrected.

`16-recurring-events-journey.md` still named the deleted
`ClassCollaborator` model; de-drifted to `Collaborator` with
`collaboratorType: CLASS` and `revenueShareBps` (#784, #772 B5).

The ~27 stale citations in `17-org-funded-checkout.md` and
`payments/05-b2c-b2b-funding-seam.md` are deliberately left alone —
they re-derive after this branch's final rebase.

Part of #1169. Closes #1013.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SbUWhJASnqTFT9evn8YJVx

---------

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Reschedule proposals cannot be answered: accept/decline/counter were never built and the consultee never sees the proposal

1 participant